﻿/*
helferlein.com ( http://www.helferlein.com )
Michael Tobisch

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions 
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Web.UI.WebControls;
using DotNetNuke.Common;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.Localization;
using helferlein.DNN.Modules.Form.Business;
using DotNetNuke.Services.Search;
using System.Collections.Generic;
using System.Web.UI.HtmlControls;
using System.IO;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Extensions;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Linq;
using System.Text;
using System.Web.UI;

namespace helferlein.DNN.Modules.Form.UI
{
   partial class FormSubmissionsEdit : PortalModuleBase
   {
#region Private Properties
      private const string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

      private FormSubmissionController _controller = null;
      private List<FormSubmissionInfo> formSubmissions;
      private Double keepDays;

      private FormSubmissionController Controller
      {
         get
         {
            if (_controller == null)
               _controller = new FormSubmissionController();
            return _controller;
         }
      }

      private FormSubmissionInfo FormSubmission { get; set; }

      private List<FormSubmissionInfo> FormSubmissions
      {
         get
         {
            if (formSubmissions == null)
            {
               if (this.SubmissionID == -1)
               {
                  if (this.CurrentOnly)
                  {
                     formSubmissions = this.Controller.Get(base.ModuleId, DateTime.Now.AddDays((-1) * this.KeepDays));
                  }
                  else
                  {
                     formSubmissions = this.Controller.GetAll(base.ModuleId);
                  }
                  if (formSubmissions.Count == 1)
                     this.SubmissionID = formSubmissions[0].FormSubmissionID;
               }
               else
               {
                  formSubmissions = new List<FormSubmissionInfo>();
                  formSubmissions.Add(this.Controller.Get(this.SubmissionID));
               }
            }
            return formSubmissions;
         }
      }

      private bool CurrentOnly
      {
         get { return Convert.ToBoolean(ViewState["CurrentOnly"]); }
         set { ViewState["CurrentOnly"] = value.ToString(); }
      }

      private Double KeepDays
      {
         get
         {
            if (Settings["KeepDays"] == null)
               keepDays = Convert.ToDouble(0);
            else
               keepDays = Convert.ToDouble(Settings["KeepDays"]);
            return keepDays;
         }
      }

      private int SubmissionID
      {
         get
         {
            object o = ViewState["SubmissionID"];
            if (o == null)
               ViewState["SubmissionID"] = "-1";
            return Convert.ToInt32(ViewState["SubmissionID"]);
         }
         set { ViewState["SubmissionID"] = value.ToString(); }
      }

      private string LocalSharedResourceFile
      {
         get { return String.Format("{0}{1}/{2}", base.ControlPath, Localization.LocalResourceDirectory, "SharedResources.resx"); }
      }
#endregion

#region Event Handlers
      protected void Page_Init(object sender, EventArgs e)
      {
         this.ChangeMode.Click += new EventHandler(this.ChangeMode_Click);
         this.ChangeApproval.Click += new EventHandler(this.ChangeApproval_Click);
         this.SetSubmissionDate.Click += new EventHandler(this.SetSubmissionDate_Click);
         this.ExcelExport.Click += new EventHandler(this.ExcelExport_Click);
         this.Cancel.Click += new EventHandler(this.Cancel_Click);
         this.Delete.Click += new EventHandler(this.Delete_Click);
         this.DeleteAll.Click += new EventHandler(this.DeleteAll_Click);
         ScriptManager scriptManager = ScriptManager.GetCurrent(base.Page);
         if (scriptManager != null)
         {
            scriptManager.RegisterPostBackControl((ImageButton)this.ExcelExport.Controls[0]);
            scriptManager.RegisterPostBackControl((LinkButton)this.ExcelExport.Controls[2]);
         }
      }

      protected void Page_Load(object sender, EventArgs e)
      {
         if (!(Page.IsPostBack))
         {
            if (Request.Params["FormSubmissionID"] != null)
               this.SubmissionID = Convert.ToInt32(Request.Params["FormSubmissionID"]);
            if ((this.FormSubmissions.Count > 0) && ((this.SubmissionID > 0) || ((this.SubmissionID == -1) && (this.FormSubmissions[this.FormSubmissions.Count - 1].FormSubmissionDate > DateTime.Now.AddDays((-1) * this.KeepDays)))))
               this.ChangeMode.Visible = false;
            foreach (HtmlTableRow row in this.SubmissionInfoTable.Rows)
            {
               row.Cells[0].Width = "20%";
               row.Cells[1].Width = "80%";
            }
            ImageButton deleteImage = (ImageButton)this.Delete.Controls[0];
            LinkButton deleteLink = (LinkButton)this.Delete.Controls[2];
            deleteImage.Attributes.Add("onClick", "javascript:return confirm('" + Localization.GetString("Delete.Confirm", base.LocalResourceFile) + "');");
            deleteLink.Attributes.Add("onClick", "javascript:return confirm('" + Localization.GetString("Delete.Confirm", base.LocalResourceFile) + "');");
            ImageButton deleteAllImage = (ImageButton)this.DeleteAll.Controls[0];
            LinkButton deleteAllLink = (LinkButton)this.DeleteAll.Controls[2];
            deleteAllImage.Attributes.Add("onClick", "javascript:return confirm('" + Localization.GetString("DeleteAll.Confirm", base.LocalResourceFile) + "');");
            deleteAllLink.Attributes.Add("onClick", "javascript:return confirm('" + Localization.GetString("DeleteAll.Confirm", base.LocalResourceFile) + "');");
            BindControls();
         }
      }

      protected void Cancel_Click(object sender, EventArgs e)
      {
         try
         {
            Response.Redirect(Globals.NavigateURL(), false);
         }
         catch (Exception ex)
         {
            Exceptions.ProcessModuleLoadException(this, ex);
         }
      }

      protected void Delete_Click(object sender, EventArgs e)
      {
         if (this.SubmissionID == -1)
         {
            this.Controller.Drop(Convert.ToInt32(this.SubmissionsList.SelectedValue));
            BindControls();
         }
         else
         {
            try
            {
               this.Controller.Drop(Convert.ToInt32(this.SubmissionID));
               Response.Redirect(Globals.NavigateURL(), false);
            }
            catch (Exception ex)
            {
               Exceptions.ProcessModuleLoadException(this, ex);
            }
         }
      }

      protected void DeleteAll_Click(object sender, EventArgs e)
      {
         try
         {
            this.Controller.DropAll(Convert.ToInt32(base.ModuleId));
            Response.Redirect(Globals.NavigateURL(), false);
         }
         catch (Exception ex)
         {
            Exceptions.ProcessModuleLoadException(this, ex);
         }
      }

      protected void SubmissionsList_SelectedIndexChanged(object sender, EventArgs e)
      {
         int formSubmissionID = Convert.ToInt32(this.SubmissionsList.SelectedValue);
         BindControls(formSubmissionID);
      }

      protected void ChangeMode_Click(object sender, EventArgs e)
      {
         this.CurrentOnly = (!(this.CurrentOnly));
         ViewState.Remove("SubmissionID");
         formSubmissions = null;
         if (this.CurrentOnly)
         {
            this.ChangeMode.ResourceKey = "ViewAll";
            this.ChangeMode.ImageUrl = "images/filter-delete.png";
            this.ChangeMode.Visible = true;
         }
         else
         {
            this.ChangeMode.ResourceKey = "CurrentOnly";
            this.ChangeMode.ImageUrl = "images/filter.png";
            if (((this.FormSubmissions[this.FormSubmissions.Count - 1].FormSubmissionDate > DateTime.Now.AddDays((-1) * this.KeepDays))) || (this.KeepDays == 0))
            {
               this.ChangeMode.Visible = false;
            }
            else
            {
               this.ChangeMode.Visible = true;
            }
         }
         BindControls();
      }

      protected void ChangeApproval_Click(object sender, EventArgs e)
      {
         int formSubmissionID;
         if (this.SubmissionID == -1)
            formSubmissionID = Convert.ToInt32(this.SubmissionsList.SelectedValue);
         else
            formSubmissionID = this.SubmissionID;
         this.FormSubmission = this.Controller.Get(formSubmissionID);
         this.FormSubmission.FormSubmissionApproved = (!(this.FormSubmission.FormSubmissionApproved));
         this.Controller.Change(this.FormSubmission);
         BindControls(formSubmissionID);
      }

      protected void SetSubmissionDate_Click(object sender, EventArgs e)
      {
         int formSubmissionID;
         if (this.SubmissionID == -1)
            formSubmissionID = Convert.ToInt32(this.SubmissionsList.SelectedValue);
         else
            formSubmissionID = this.SubmissionID;
         this.FormSubmission = this.Controller.Get(formSubmissionID);
         this.FormSubmission.FormSubmissionApproved = true;
         this.FormSubmission.FormSubmissionDate = DateTime.Now;
         this.Controller.Change(this.FormSubmission);
         BindControls(formSubmissionID);
      }

      protected void ExcelExport_Click(object sender, EventArgs e)
      {
         this.ExportToExcel();
      }
#endregion

#region Private Methods
      private void BindControls(int formSubmissionID)
      {
         if (this.SubmissionID == -1)
         {
            Dictionary<int, string> submissionsList = new Dictionary<int, string>();
            foreach (FormSubmissionInfo fsi in this.FormSubmissions)
            {
               submissionsList.Add(fsi.FormSubmissionID, String.Format("[{0}] ({1:d} {1:t}) {2}", GetSubmissionStatus(fsi), fsi.FormSubmissionDate, Server.HtmlDecode(GetItemToAdd(fsi)).Trim()));
            }
            this.SubmissionsList.DataSource = submissionsList;
            this.SubmissionsList.DataValueField = "key";
            this.SubmissionsList.DataTextField = "value";
            if (formSubmissionID > -1)
               this.SubmissionsList.SelectedValue = formSubmissionID.ToString();
            this.SubmissionsList.DataBind();
         }
         DisplayControls(this.FormSubmissions.Count > 0);
      }

      private void BindControls()
      {
         BindControls(this.SubmissionID);
      }

      private void DisplayControls(bool submissionsExist)
      {
         if (submissionsExist)
         {
            if (this.SubmissionID == -1)
            {
               this.FormSubmission = this.Controller.Get(Convert.ToInt32(this.SubmissionsList.SelectedValue));
               this.SubmissionsList.Visible = true;
            }
            else
            {
               this.FormSubmission = this.Controller.Get(Convert.ToInt32(this.SubmissionID));
               this.SubmissionsList.Visible = false;
            }

            this.Delete.Visible = true;
            this.DeleteAll.Visible = true;
            this.DateCaptionLabel.Text = Localization.GetString("DateCaptionLabel.Text", LocalResourceFile);
            this.DateLabel.Text = String.Format("{0:d}", this.FormSubmission.FormSubmissionDate);
            if (this.FormSubmission.FormSubmissionDate > DateTime.Now.AddDays((-1) * this.KeepDays))
            {
               this.DateLabel.CssClass = "Normal";
               this.ChangeApproval.Visible = true;
               this.SetSubmissionDate.Visible = false;
            }
            else
            {
               this.DateLabel.CssClass = "NormalRed";
               this.ChangeApproval.Visible = false;
               this.SetSubmissionDate.Visible = true;
            }
            this.TimeCaptionLabel.Text = Localization.GetString("TimeCaptionLabel.Text", LocalResourceFile);
            this.TimeLabel.Text = String.Format("{0:t}", this.FormSubmission.FormSubmissionDate);
            this.RemoteIPCaptionLabel.Text = Localization.GetString("RemoteIPCaptionLabel.Text", this.LocalSharedResourceFile);
            this.RemoteIPLabel.Text = this.FormSubmission.FormSubmissionIPAddress;
            this.ApprovedCaptionLabel.Text = Localization.GetString("ApprovedCaptionLabel.Text", LocalResourceFile);
            this.ApprovedCheckBox.Checked = this.FormSubmission.FormSubmissionApproved;
            this.SubmissionLabel.Text = this.FormSubmission.ToHtml(false, false, true, true);
            if (this.FormSubmission.FormSubmissionApproved)
            {
               this.ChangeApproval.ResourceKey = "RemoveApproval";
               this.ChangeApproval.ImageUrl = "images/untick.png";
            }
            else
            {
               this.ChangeApproval.ResourceKey = "Approve.Text";
               this.ChangeApproval.ImageUrl = "images/tick.png";
            }
         }
         else
         {
            this.SubmissionsList.Visible = false;
            this.SubmissionInfoTable.Visible = false;
            if (!(this.CurrentOnly))
               this.ChangeMode.Visible = false;
            else
            {
               if (this.KeepDays == 0)
                  this.ChangeMode.Visible = false;
               else
                  this.ChangeMode.Visible = true;
            }
            this.ChangeApproval.Visible = false;
            this.SetSubmissionDate.Visible = false;
            this.ExcelExport.Visible = false;
            this.Delete.Visible = false;
            this.DeleteAll.Visible = false;
            this.SubmissionLabel.Text = Localization.GetString("NoItems.Text", LocalResourceFile);
         }
      }

      private string GetItemToAdd(FormSubmissionInfo fsi)
      {
         return fsi.ItemToAddValue;
      }

      private string GetSubmissionStatus(FormSubmissionInfo fsi)
      {
         string result = string.Empty;
         if (fsi.FormSubmissionDate.AddDays(this.KeepDays) < DateTime.Now)
            result = "O";
         else
            result = (fsi.FormSubmissionApproved ? "A" : "X");
         return result;
      }
#endregion

#region Export Excel
      private void ExportToExcel()
      {
         if (this.FormSubmissions.Count > 0)
         {
            int currentSheet = 1;
            int rowNumber = 2;
            StringBuilder currentForm = new StringBuilder(this.formSubmissions[0].GetBasicForm());

            MemoryStream stream = SpreadsheetReader.Create();
            SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, true);

            // Delete current sheets
            IEnumerable<Sheet> sheets = doc.WorkbookPart.Workbook.Descendants<Sheet>();
            int sheetsCount = sheets.Count();
            if (sheetsCount > 0)
            {
               for (int i = sheetsCount; i > 0; i--)
               {
                  doc.WorkbookPart.DeletePart(sheets.ElementAt(i - 1).Id);
                  doc.WorkbookPart.Workbook.Sheets.RemoveChild<Sheet>(sheets.ElementAt(i - 1));
                  doc.WorkbookPart.Workbook.Save();
               }
            }


            // Write Labels
            WorksheetPart worksheetpart = this.NewWorksheetPart(this.formSubmissions[0].GetSubmissionFromXml(), doc, currentSheet);
            this.WriteRow(worksheetpart, this.formSubmissions[0].GetSubmissionFromXml(), doc, rowNumber++);

            for (int i = 1; i < this.FormSubmissions.Count; i++)
            {
               StringBuilder thisForm = new StringBuilder(this.formSubmissions[i].GetBasicForm());
               if (thisForm.ToString() != currentForm.ToString())
               {
                  currentForm.Remove(0, currentForm.Length);
                  currentForm.Append(thisForm.ToString());
                  worksheetpart = this.NewWorksheetPart(this.formSubmissions[0].GetSubmissionFromXml(), doc, ++currentSheet);
                  rowNumber = 2;
               }
               this.WriteRow(worksheetpart, this.formSubmissions[i].GetSubmissionFromXml(), doc, rowNumber++);
            }

            // Save to the memory stream
            SpreadsheetWriter.Save(doc);

            // Write to response stream
            Response.Clear();
            Response.AddHeader("content-disposition", String.Format("attachment;filename={0}", "helferlein_Form.xlsx"));
            Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

            stream.WriteTo(Response.OutputStream);
            Response.End();
         }
      }

      private WorksheetPart NewWorksheetPart(List<FormItemInfo> theForm, SpreadsheetDocument doc, int currentSheet)
      {
         WorksheetPart worksheetPart = SpreadsheetWriter.InsertWorksheet(doc, String.Format("{0}{1}", Localization.GetString("Sheet.Text", base.LocalResourceFile), currentSheet));
         WorksheetWriter writer = new WorksheetWriter(doc, worksheetPart);

         SpreadsheetStyle boldStyle = SpreadsheetReader.GetDefaultStyle(doc);
         boldStyle.IsBold = true;

         string columnLetter = "A";

         foreach (FormItemInfo fii in theForm)
         {
            if (fii.FormItemType != FormItemType.Label)
            {
               writer.PasteText(String.Format("{0}1", columnLetter), Server.HtmlDecode(fii.FormItemLabel), boldStyle);
               columnLetter = this.GetNextColumnLetter(columnLetter);
               if (fii.FormItemType == FormItemType.RadioButtonList || fii.FormItemType == FormItemType.MultipleSelect)
               {
                  if (!String.IsNullOrEmpty(fii.FormItemOtherValue))
                  {
                     writer.PasteText(String.Format("{0}1", columnLetter), Server.HtmlDecode(Localization.GetString("Other.Text", this.LocalSharedResourceFile)), boldStyle);
                     columnLetter = this.GetNextColumnLetter(columnLetter);
                  }
               }
            }
         }
         return worksheetPart;
      }

      private void WriteRow(WorksheetPart worksheetPart, List<FormItemInfo> theForm, SpreadsheetDocument doc, int rowNumber)
      {
         WorksheetWriter writer = new WorksheetWriter(doc, worksheetPart);

         string columnLetter = "A";

         foreach (FormItemInfo fii in theForm)
         {
            if (fii.FormItemType != FormItemType.Label)
            {
               switch (fii.FormItemType)
               {
                  case FormItemType.Date:
                     if (!(String.IsNullOrEmpty(fii.FormItemSelectedValue)))
                        writer.PasteDate(String.Format("{0}{1}", columnLetter, rowNumber), DateTime.FromBinary(Convert.ToInt64(fii.FormItemSelectedValue)));
                     break;
                  case FormItemType.Checkbox:
                     writer.PasteText(String.Format("{0}{1}", columnLetter, rowNumber), (Convert.ToBoolean(fii.FormItemSelectedValue)) ? Server.HtmlDecode(Localization.GetString("Yes.Text")) : Server.HtmlDecode(Localization.GetString("No.Text")));
                     break;
                  case FormItemType.RadioButtonList:
                  case FormItemType.MultipleSelect:
                     writer.PasteText(String.Format("{0}{1}", columnLetter, rowNumber), Server.HtmlDecode(fii.FormItemSelectedValue));
                     columnLetter = this.GetNextColumnLetter(columnLetter);
                     writer.PasteText(String.Format("{0}{1}", columnLetter, rowNumber), Server.HtmlDecode(fii.FormItemOtherValue));
                     break;
                  default:
                     writer.PasteText(String.Format("{0}{1}", columnLetter, rowNumber), Server.HtmlDecode(fii.FormItemSelectedValue));
                     break;
               }
               columnLetter = this.GetNextColumnLetter(columnLetter);
            }
         }
      }

      private string GetNextColumnLetter(string columnLetter)
      {
         string result;
         int[] index = new int[] { 0, 0, 0 };
         switch (columnLetter.Length)
         {
            case 1:
               index[0] = ALPHABET.IndexOf(columnLetter);
               if (index[0] < ALPHABET.Length - 1)
                  result = ALPHABET.Substring(index[0] + 1, 1);
               else
                  result = "AA";
               break;
            case 2:
               index[0] = ALPHABET.IndexOf(columnLetter.Substring(0, 1));
               index[1] = ALPHABET.IndexOf(columnLetter.Substring(1, 1));
               if ((index[0] < ALPHABET.Length - 1) && (index[1] < ALPHABET.Length - 1))
               {
                  if (index[1] == ALPHABET.Length - 1)
                     result = String.Format("{0}A", ALPHABET.Substring(index[0] + 1, 1));
                  else
                     result = String.Format("{0}{1}", ALPHABET.Substring(index[0], 1), ALPHABET.Substring(index[1] + 1, 1));
               }
               else
                  result = "AAA";
               break;
            default:
               if (columnLetter != "XFD")
               {
                  index[0] = ALPHABET.IndexOf(columnLetter.Substring(0, 1));
                  index[1] = ALPHABET.IndexOf(columnLetter.Substring(1, 1));
                  index[2] = ALPHABET.IndexOf(columnLetter.Substring(2, 1));

                  if (index[2] == ALPHABET.Length - 1)
                  {
                     if (index[1] == ALPHABET.Length - 1)
                        result = String.Format("{0}AA", ALPHABET.Substring(index[0] + 1, 1));
                     else
                        result = String.Format("{0}{1}A", ALPHABET.Substring(index[0], 1), ALPHABET.Substring(index[1] + 1, 1));
                  }
                  else
                     result = String.Format("{0}{1}{2}", ALPHABET.Substring(index[0], 1), ALPHABET.Substring(index[1], 1), ALPHABET.Substring(index[2] + 1, 1));
               }
               else
               {
                  throw new Exception("Cannot create column letters beyond XFD");
               }
               break;
         }
         return result;
      }
#endregion
   }
}
